package io.lvdaxian.mybatis19.reflection.factory;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.util.*;

/**
 * 表示默认的 对象工厂
 *
 * @author lihh
 */
public class DefaultObjectFactory implements ObjectFactory, Serializable {
  
  private static final long serialVersionUID = -8855120656740914948L;
  
  @Override
  public void setProperties(Properties properties) {
    // no props for default 默认无属性可设置
  }
  
  @Override
  public <T> T create(Class<T> type) {
    return create(type, null, null);
  }
  
  /**
   * 根据 Class 以及构造类型 构造参数 创建实例
   *
   * @param type                Object type
   * @param constructorArgTypes Constructor argument types
   * @param constructorArgs     Constructor argument values
   * @param <T>                 泛型
   * @return 创建的对象
   * @author lihh
   */
  @Override
  public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
    // 1. 解析接口
    Class<?> classToCreate = resolveInterface(type);
    // 2. 类实例化
    return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
  }
  
  /**
   * 这里是 实例化类的方法
   *
   * @param type                类 类型
   * @param constructorArgTypes 构造参数类型
   * @param constructorArgs     具体的构造参数
   * @param <T>                 动态泛型
   * @return 返回类类实例
   * @author lihh
   */
  private <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
    try {
      Constructor<T> constructor;
      //如果没有传入constructor，调用空构造函数，核心是调用Constructor.newInstance
      if (constructorArgTypes == null || constructorArgs == null) {
        constructor = type.getDeclaredConstructor();
        if (!constructor.isAccessible()) {
          constructor.setAccessible(true);
        }
        return constructor.newInstance();
      }
      // 如果传入constructor，调用传入的构造函数，核心是调用Constructor.newInstance
      constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));
      if (!constructor.isAccessible()) {
        constructor.setAccessible(true);
      }
      // 构建有参实例
      return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
    } catch (Exception e) {
      // 如果出错，包装一下，重新抛出自己的异常
      StringBuilder argTypes = new StringBuilder();
      if (constructorArgTypes != null) {
        for (Class<?> argType : constructorArgTypes) {
          argTypes.append(argType.getSimpleName());
          argTypes.append(",");
        }
      }
      StringBuilder argValues = new StringBuilder();
      if (constructorArgs != null) {
        for (Object argValue : constructorArgs) {
          argValues.append(argValue);
          argValues.append(",");
        }
      }
      throw new RuntimeException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);
    }
  }
  
  
  @Override
  public <T> boolean isCollection(Class<T> type) {
    // 判断 type 是否能赋值给 Collection
    return Collection.class.isAssignableFrom(type);
  }
  
  /**
   * 解析接口，将 interface 转换为实际的 class 类, 其实就是特定的Class类型转换
   *
   * @author lihh
   */
  protected Class<?> resolveInterface(Class<?> type) {
    Class<?> classToCreate;
    if (type == List.class || type == Collection.class || type == Iterable.class) {
      // List|Collection|Iterable-->ArrayList
      classToCreate = ArrayList.class;
    } else if (type == Map.class) {
      // Map->HashMap
      classToCreate = HashMap.class;
    } else if (type == SortedSet.class) {
      // SortedSet->TreeSet
      classToCreate = TreeSet.class;
    } else if (type == Set.class) {
      // Set->HashSet
      classToCreate = HashSet.class;
    } else {
      // 除此以外，就用原来的类型
      classToCreate = type;
    }
    return classToCreate;
  }
}
